/* $Id: SvgaHw.h $ */
/** @file
 * VirtualBox Windows Guest Mesa3D - Gallium driver VMSVGA hardware access helpers.
 */

/*
 * Copyright (C) 2016-2020 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef _WDDM_INCLUDE_GALLIUM_SVGAHW_H_
#define _WDDM_INCLUDE_GALLIUM_SVGAHW_H_

#include "trace.h"
#include "Svga.h"
#include "asm.h"
#include "svga_reg.h"

DECLINLINE(UINT64) SVGAPort(PVBOXWDDM_EXT_VMSVGA pSvga, UINT16 u16Offset)
{
    return (UINT64)((char*)pSvga->pu32SysIO + u16Offset);
}

DECLINLINE(void) SVGAPortWrite(PVBOXWDDM_EXT_VMSVGA pSvga, UINT16 u16Offset, UINT32 u32Value)
{
    WRITE_REGISTER_ULONG((PULONG)SVGAPort(pSvga, u16Offset), u32Value);
}

DECLINLINE(UINT32) SVGAPortRead(PVBOXWDDM_EXT_VMSVGA pSvga, UINT16 u16Offset)
{
    UINT32 u32Value = 0;

    u32Value = READ_REGISTER_ULONG((PULONG)SVGAPort(pSvga, u16Offset));

    return u32Value;
}

DECLINLINE(volatile void *) SVGAFifoPtrFromOffset(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Offset)
{
    return (volatile UINT8 *)pSvga->pu32FIFO + u32Offset;
}

DECLINLINE(volatile void *) SVGAFifoPtrFromIndex(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Index)
{
    return pSvga->pu32FIFO + u32Index;
}

DECLINLINE(UINT32) SVGAFifoRead(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Index)
{
    volatile UINT32 *pu32 = &pSvga->pu32FIFO[u32Index];
    return ASMAtomicReadU32(pu32);
}

DECLINLINE(void) SVGAFifoWrite(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Index, UINT32 u32Value)
{
    volatile UINT32 *pu32 = &pSvga->pu32FIFO[u32Index];
    ASMAtomicWriteU32(pu32, u32Value);
}

DECLINLINE(void) SVGARegisterIndexWrite(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Value)
{
    SVGAFifoWrite(pSvga, SVGA_FIFO_REGISTER_INDEX, u32Value);
}

DECLINLINE(void) SVGARegWrite(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Offset, UINT32 u32Value)
{
    KIRQL OldIrql;
    KeAcquireSpinLock(&pSvga->HwSpinLock, &OldIrql);

    SVGARegisterIndexWrite(pSvga, u32Offset);
    if (u32Offset != SVGA_REG_SYNC) {
        SVGAPortWrite(pSvga, SVGA_VALUE_PORT, u32Value);
    }

    KeReleaseSpinLock(&pSvga->HwSpinLock, OldIrql);
}

DECLINLINE(UINT32) SVGARegRead(PVBOXWDDM_EXT_VMSVGA pSvga, UINT32 u32Offset)
{
    KIRQL OldIrql;
    KeAcquireSpinLock(&pSvga->HwSpinLock, &OldIrql);

    SVGARegisterIndexWrite(pSvga, u32Offset);
    const UINT32 u32Value = SVGAPortRead(pSvga, SVGA_VALUE_PORT);

    KeReleaseSpinLock(&pSvga->HwSpinLock, OldIrql);
    return u32Value;
}

#endif
